<!-- 表单 》 图片 -->

<template>
  <el-form-item v-bind="formItem">
    <!-- 标签 -->
    <template v-if="hasLabelSlot" #label>
      <slot name="label" :label="formItem.label">{{ formItem.label }}</slot>
    </template>

    <draggable v-model="model" v-bind="draggableProps" @end="draged">
      <!-- 预览图列表 (拖拽项) -->
      <div v-for="(url, i) in urlList" :key="url" :class="imageClass" :style="imageStyle">
        <div :class="delClass" @click="toDel(i)">
          <img v-if="ICON.delImg" :src="ICON.delImg" />
          <i v-else :class="ICON.delIcon" />
        </div>

        <el-image :src="url" :fit="fit" :preview-src-list="urlList" />
      </div>

      <!-- 上传组件 (不可拖拽) -->
      <template #footer>
        <div :class="uploadClass" :style="imageStyle">
          <el-upload v-bind="uploadProps">
            <div>
              <img v-if="ICON.upImg" :src="ICON.upImg" />
              <i v-else :class="ICON.upIcon" />

              <div v-if="text">{{ text }}</div>
            </div>
          </el-upload>
        </div>
      </template>
    </draggable>
  </el-form-item>
</template>

<script>
// ============================== 导入依赖 ============================== //

import CORE from '@/CORE'
import mixForm from '../mixForm'
import FormFile from '../FormFile'
import draggable from 'vuedraggable'
import UTIL from '../../row/RowOperate/UTIL'

const name = 'FormImage'

// ============================== 导出组件 ============================== //

export default {
  /**
   * 名称定义 (实际使用名称)
   */
  name,

  /**
   * 混入列表 (配置选项合并)
   */
  mixins: [mixForm],

  /**
   * 组件导入 (Abc.vue + Abc/index.vue)
   */
  ...CORE.components(draggable),

  /**
   * 属性注册 (抽取以便查阅)
   */
  props: CORE.WEB[name],

  /**
   * 状态数据 (函数返回对象)
   */
  data() {
    return {
      model: [], // 内部绑定值
      EMPTY: [], // 空值常量
    }
  },

  /**
   * 计算属性 (慎用箭头函数)
   */
  computed: {
    /**
     * 上传类型
     */
    uploadType: FormFile.computed.uploadType,

    /**
     * 业务标识
     */
    businessTag: FormFile.computed.businessTag,

    /**
     * 图标对象
     */
    ICON() {
      const { img, icon, delImg, delIcon } = this
      return {
        upImg: UTIL.getImg(img),
        upIcon: UTIL.getImg(icon) || 'el-icon-upload',
        delImg: UTIL.getImg(delImg),
        delIcon: UTIL.getImg(delIcon) || 'el-icon-close',
      }
    },

    /**
     * 填充属性
     */
    fit() {
      const { cover, contain, fill, initFit } = this
      if (cover) return 'cover'
      if (contain) return 'contain'
      if (fill) return 'fill'
      if (initFit) return initFit
      return null
    },

    /**
     * 路径列表
     */
    urlList() {
      const { model, pathTrans, noTrans } = this
      if (noTrans) return model
      return model.map((url) => pathTrans(url))
    },

    /**
     * 图片样式类
     */
    imageClass() {
      const { className } = this
      return `${className}-image`
    },

    /**
     * 图片样式对象
     */
    imageStyle() {
      const { getSize, square, gap } = this
      const [w, h] = CORE.isArray(square) ? square : [square, square]
      const width = getSize(w)
      const height = getSize(h)
      const gapStr = getSize(gap)
      const margin = `0 ${gapStr} ${gapStr} 0`
      return { width, height, margin }
    },

    /**
     * 删除的样式类
     */
    delClass() {
      const { className, commonProps, noDel, allDel } = this
      if (noDel || commonProps.disabled) return `${className}-del ${className}-del-hide`
      if (allDel) return `${className}-del ${className}-del-show`
      return `${className}-del`
    },

    /**
     * 上传属性
     */
    uploadProps() {
      const { elProps, accept, beforeUpload } = this
      return {
        ...elProps,
        action: '',
        drag: true,
        showFileList: false,
        accept,
        beforeUpload,
      }
    },

    /**
     * 拖拽属性
     */
    draggableProps() {
      const { dragProps, animation, commonProps, getSize, gap, imageClass } = this
      const gapStr = getSize(gap)
      return {
        ...dragProps,
        animation,
        disabled: commonProps.disabled,
        class: commonProps.class,
        style: { margin: `0 -${gapStr} -${gapStr} 0` },
        draggable: `.${imageClass}`,
      }
    },

    /**
     * 上传样式类
     */
    uploadClass() {
      const { className, commonProps, model, limit } = this
      const needHide = commonProps.disabled || (limit && model.length >= limit)
      if (needHide) return `${className}-upload ${className}-upload-hide`
      return `${className}-upload`
    },
  },

  /**
   * 本地方法 (轻量重要在前)
   */
  methods: {
    /**
     * 是否不等 (可覆盖)
     */
    isDiff() {
      const { obj, prop, model, join } = this
      const value = obj[prop]

      // 无值 (如 undefined / null / '' / [] 等)
      if (CORE.isEmpty(value)) return !CORE.isEmpty(model)

      // 有值
      if (join) return value !== model.join()
      else return value.join() !== model.join()
    },

    /**
     * 设置内部绑定值 (可覆盖)
     */
    setModel() {
      const { obj, prop, join, init, EMPTY } = this
      const value = obj[prop]

      if (CORE.isEmpty(value)) this.model = init || EMPTY
      else this.model = join ? value.split(',') : value
    },

    /**
     * 检查文件
     */
    checkFile(file) {
      const { max, maxErrPrefix, maxErrSuffix, jpg, png, svg } = this
      let msgError

      if (max && file.size > max * 1048576) msgError = `${maxErrPrefix} ${max} ${maxErrSuffix}`
      else if (jpg && !/\.jp(e)?g$/.test(file.name)) msgError = '请上传 .jpg 或 .jpeg 格式的图片'
      else if (png && !/\.png$/.test(file.name)) msgError = '请上传 .png 格式的图片'
      else if (svg && !/\.svg$/.test(file.name)) msgError = '请上传 .svg 格式的图片'
      else if (!CORE.MAP.REG_IMAGE.test(file.name)) msgError = '请上传图片格式的文件'

      msgError && CORE.MSG.error(msgError)

      return !msgError
    },

    /**
     * 获取文件夹
     */
    getFolder: FormFile.methods.getFolder,

    /**
     * 上传之前
     */
    beforeUpload(file) {
      if (!this.checkFile(file)) return false

      const folder = this.getFolder()
      const tag = this.businessTag
      const type = this.uploadType

      const success = (url) => {
        this.model.push(url || this.EMPTY)
        this.emitChange()
      }
      const error = (err) => CORE.MSG.error(err.message || '上传失败')

      if (this.upload) this.upload(file, folder, tag, type).then(success).catch(error)
      else CORE.imageUpload(file, folder, tag).then(success).catch(error)

      return false
    },

    /**
     * 拖拽完成
     */
    draged() {
      const { emitChange } = this
      emitChange()
    },

    /**
     * 点击删除
     */
    toDel(i) {
      const { emitChange } = this
      this.model.splice(i, 1)
      emitChange()
    },
  },
}
</script>
